package cn.imatu.framework.oss.manager;

import cn.hutool.core.util.RandomUtil;
import cn.imatu.framework.exception.BizException;
import cn.imatu.framework.oss.utils.OssUtils;
import cn.imatu.framework.storage.base.config.AliyunStorageProperties;
import cn.imatu.framework.storage.base.config.StorageProperties;
import cn.imatu.framework.storage.base.constants.FileStorageEnum;
import cn.imatu.framework.storage.base.manager.BaseStorageManager;
import cn.imatu.framework.tool.core.StringUtils;
import cn.imatu.framework.tool.core.UrlUtils;
import cn.imatu.framework.tool.core.exception.Assert;
import cn.imatu.framework.tool.core.file.FileUtils;
import cn.imatu.framework.tool.core.file.MimeTypesUtils;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.google.common.collect.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.function.Consumer;

/**
 * @author shenguangyang
 */
public class AliyunStorageManager extends BaseStorageManager {
    private static final Logger log = LoggerFactory.getLogger(AliyunStorageManager.class);
    /**
     * 批量删除组大小
     */
    private static final Integer DELETE_BATCH_GROUP_SIZE = 900;

    @Resource
    private StorageProperties storageProperties;

    @Resource
    private AliyunStorageProperties aliyunStorageProperties;

    @Override
    public void createClient(String accessKey, String secretKey) throws Exception {
        log.info("开始初始化oss");
        String endpoint = aliyunStorageProperties.getEndpoint();
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKey, secretKey);

        if (storageProperties.getInitBucket()) {
            String bucketName = aliyunStorageProperties.getBucketName();
            boolean exists = ossClient.doesBucketExist(bucketName);
            //判定是否存在此存储空间
            if (!exists) {
                // 创建存储空间。
                log.info("oss创建bucket: {}", bucketName);
                ossClient.createBucket(bucketName);
                return;
            }
            log.info("oss存在bucket: {}", bucketName);
        }

        OssUtils.init(ossClient, aliyunStorageProperties);
        log.info("oss初始化完成");
    }

    @Override
    public String getIntranetUrl(String bucketName, String objectName) {
        String endpoint = aliyunStorageProperties.getEndpoint();
        if (endpoint.startsWith("https://")) {
            String url = endpoint.replace("https://", "https://" + bucketName + ".") + "/" + objectName;
            return UrlUtils.removeRepeatSlashOfUrl(url);
        } else if (endpoint.startsWith("http://")) {
            String url = endpoint.replace("http://", "http://" + bucketName + ".") + "/" + objectName;
            return UrlUtils.removeRepeatSlashOfUrl(url);
        } else {
            throw new BizException("aliyun 端点地址不是以http(s)://开头, 请检查");
        }
    }

    @Override
    public void uploadText(String text, String objectName) {
        String bucketName = aliyunStorageProperties.getBucketName();
        InputStream inputStream = new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8));
        OssUtils.upload(inputStream, bucketName, objectName, "text/plain");
    }

    @Override
    public void uploadFile(InputStream inputStream, String contentType, String objectName) throws Exception {
        String bucketName = aliyunStorageProperties.getBucketName();
        OssUtils.upload(inputStream, bucketName, objectName, contentType);
    }

    @Override
    public void uploadFile(String bucketName, InputStream inputStream, String contentType, String objectName) throws Exception {
        OssUtils.upload(inputStream, bucketName, objectName, contentType);
    }

    @Override
    public void uploadDir(String dirPath) {
        List<String> allFileList = FileUtils.getAllFile(dirPath, false, null);
        dirPath = dirPath.replace("\\", "/");

        if (!dirPath.endsWith("/")) {
            dirPath = dirPath + "/";
        }

        for (String filePath : allFileList) {
            String path = filePath.replace("\\", "/").replace(dirPath, "");

            // 针对win路径进行处理
            if (path.contains(":")) {
                path = path.substring(path.lastIndexOf(":") + 1);
            }

            String objectName = path;
            try (InputStream inputStream = Files.newInputStream(Paths.get(filePath))) {
                uploadFile(inputStream, MimeTypesUtils.getInstance().getMimetype(FileUtils.getName(filePath)), objectName);
            } catch (Exception e) {
                log.error("error: ", e);
            }
        }
    }

    @Override
    public String getObjectUrl(String objectName) {
        String bucketName = aliyunStorageProperties.getBucketName();
        String url = OssUtils.getAccessURL(bucketName, objectName);
        Assert.notEmpty(url, "获取url失败");
        return url;
    }

    @Override
    public InputStream getFile(String objectName) {
        String bucketName = aliyunStorageProperties.getBucketName();
        return OssUtils.getFile(bucketName, objectName);
    }

    @Override
    public List<String> listFilePath(String pathPrefix) {
        String bucketName = aliyunStorageProperties.getBucketName();

        // 移除前后两个 /
        pathPrefix = StringUtils.removeEnd(pathPrefix, "/");
        pathPrefix = StringUtils.removeStart(pathPrefix, "/");
        return OssUtils.getFilePathList(bucketName, pathPrefix, null);
    }

    @Override
    public List<String> listFilePath(String pathPrefix, Consumer<String> filePathCallback) {
        String bucketName = aliyunStorageProperties.getBucketName();

        // 移除前后两个 /
        pathPrefix = StringUtils.removeEnd(pathPrefix, "/");
        pathPrefix = StringUtils.removeStart(pathPrefix, "/");
        return OssUtils.getFilePathList(bucketName, pathPrefix, filePathCallback);
    }

    @Override
    public Boolean createBucket(Boolean randomSuffix) {
        String bucketName = aliyunStorageProperties.getBucketName();
        try {
            if (randomSuffix != null && randomSuffix) {
                return OssUtils.createBucket(bucketName + "-" + RandomUtil.randomString(8));
            }
            return OssUtils.createBucket(bucketName);
        } catch (Exception e) {
            log.error("createBucket::bucketName = [{}] message = {}", bucketName, e.getMessage());
            return false;
        }
    }

    @Override
    public Boolean createBucket(String bucketName) {
        try {
            return OssUtils.createBucket(bucketName);
        } catch (Exception e) {
            log.error("createBucket::bucketName = [{}] message = {}", bucketName, e.getMessage());
            return false;
        }
    }

    @Override
    public Boolean doesBucketExist(String bucketName) {
        try {
            return OssUtils.doesBucketExist(bucketName);
        } catch (Exception e) {
            log.error("doesBucketExist::bucketName = [{}] message = {}", bucketName, e.getMessage());
            return false;
        }
    }

    /**
     * 一次最大删除900左右文件
     *
     * @param objectNameList 对象名集合
     * @throws BizException 异常
     */
    @Override
    public void deleteObjects(List<String> objectNameList) throws BizException {
        String bucketName = aliyunStorageProperties.getBucketName();
        for (List<String> groupObjectNames : Lists.partition(objectNameList, DELETE_BATCH_GROUP_SIZE)) {
            int deleteSize = OssUtils.deleteObjects(bucketName, groupObjectNames);
            if (deleteSize != groupObjectNames.size()) {
                throw new BizException("实际删除的文件数量: " + deleteSize + ", 目标删除文件数量: " + groupObjectNames.size());
            }
        }
    }

    @Override
    public void deleteObjects(String bucketName, List<String> objectNameList) throws Exception {
        for (List<String> groupObjectNames : Lists.partition(objectNameList, DELETE_BATCH_GROUP_SIZE)) {
            int deleteSize = OssUtils.deleteObjects(bucketName, groupObjectNames);
            if (deleteSize != groupObjectNames.size()) {
                throw new BizException("实际删除的文件数量: " + deleteSize + ", 目标删除文件数量: " + groupObjectNames.size());
            }
        }
    }

    @Override
    public void deleteObject(String objectName) throws Exception {
        String bucketName = aliyunStorageProperties.getBucketName();
        OssUtils.deleteObject(bucketName, objectName);
    }

    @Override
    public void deleteObject(String bucketName, String objectName) throws Exception {
        OssUtils.deleteObject(bucketName, objectName);
    }

    @Override
    public boolean checkFileIsExist(String objectName) {
        String bucketName = aliyunStorageProperties.getBucketName();
        return OssUtils.objectExist(bucketName, objectName);
    }

    @Override
    public boolean checkFolderIsExist(String folderName) {
        return super.checkFolderIsExist(folderName);
    }

    @Override
    public FileStorageEnum storageType() {
        return FileStorageEnum.ALIYUN;
    }
}
